package edu.algo3.algoThief.domain;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import edu.algo3.algoThief.dao.Repositorio;
import edu.algo3.algoThief.util.Constants;

public class Jugador {

    private String nombre;

    private Tiempo tiempo;

    private OrdenDeArresto ordenDeArresto;

    private Integer arrestos;

    private ContextoDelJuego contextoDelJuego;

    private Ciudad ciudadActual;

    private Ciudad ciudadDestinoPorMalViaje;

    private Pista pistaActual;

    private List<Ciudad> destinos;

    private int numeroDeEdificiosVisitados;

    private boolean yaHeridoConCuchillo;

    private boolean estaEnCiudadIncorrecta = Boolean.FALSE;

    public Jugador(String nombre, Integer arrestos) {

        this.nombre = nombre;
        this.arrestos = arrestos;
        this.comenzarNuevoJuego();

        this.numeroDeEdificiosVisitados = 0;
        this.yaHeridoConCuchillo = false;
    }

    public Jugador(String nombre) {

        this.nombre = nombre;
        this.arrestos = Repositorio.cargarJugadorArrestos(nombre);
        this.cargarJuego();

        this.numeroDeEdificiosVisitados =
            Repositorio.cargarJugadorNumeroDeEdificiosVisitados(this.nombre);
        this.yaHeridoConCuchillo =
            Repositorio.cargarJugadorYaHeridoConCuchillo(this.nombre);
        this.estaEnCiudadIncorrecta =
            Repositorio.cargarEstaEnCiudadIncorrecta(this.nombre);
    }

    public String getNombre() {

        return nombre;
    }

    public Tiempo getTiempo() {

        return tiempo;
    }

    public OrdenDeArresto getOrdenDeArresto() {

        return ordenDeArresto;
    }

    public Integer getArrestos() {

        return arrestos;
    }

    public ContextoDelJuego getContextoDelJuego() {

        return contextoDelJuego;
    }

    public Ciudad getCiudadActual() {

        return ciudadActual;
    }

    public int getNumeroDeEdificiosVisitados() {

        return numeroDeEdificiosVisitados;
    }

    public boolean getYaHeridoConCuchillo() {

        return yaHeridoConCuchillo;
    }

    // setters

    public void setNombre(String nombre) {

        this.nombre = nombre;
    }

    public void setTiempo(Tiempo tiempo) {

        this.tiempo = tiempo;
    }

    public void setOrdenDeArresto(OrdenDeArresto ordenDeArresto) {

        this.ordenDeArresto = ordenDeArresto;
    }

    public void setArrestos(Integer arrestos) {

        this.arrestos = arrestos;
    }

    public void setContextoDelJuego(ContextoDelJuego contextoDelJuego) {

        this.contextoDelJuego = contextoDelJuego;
    }

    public void setCiudadActual(Ciudad ciudadActual) {

        this.ciudadActual = ciudadActual;
    }

    /**
     * @return the ciudadDestinoPorMalViaje
     */
    public Ciudad getCiudadDestinoPorMalViaje() {

        return ciudadDestinoPorMalViaje;
    }

    /**
     * @return the viajoACiudadIncorrecta
     */
    public boolean estaEnCiudadIncorrecta() {

        return estaEnCiudadIncorrecta;
    }

    public List<Ciudad> getDestinos() {

        return destinos;
    }

    // metodos

    /**
     * @return the pistaActual
     */
    public Pista getPistaActual() {

        return pistaActual;
    }

    public void comenzarNuevoJuego() {

        this.tiempo = new Tiempo(); // TIEMPO INICIAL DE 154hs (JUEGO NUEVO)
        this.contextoDelJuego = new ContextoDelJuego(this.arrestos);
        this.ordenDeArresto = new OrdenDeArresto();
        // LA CIUDAD ACTUAL (DONDE COMIENZA EL JUEGO) SERA EL PRIMER EDIFICIO DE LA RUTA DE ESCAPE
        // DEL LADRON
        this.ciudadActual =
            this.getContextoDelJuego().getCaso().getSiguienteCiudadDeEscape();
        this.ciudadActual.setVisitada(Boolean.TRUE); // Primera ciudad se visita ni bien comienza el
                                                     // juego
        this.pistaActual = new Pista();
        this.actualizarDestinos();
    }

    public void cargarJuego() {

        this.tiempo = new Tiempo(Repositorio.cargarTiempo(this.nombre)); // TIEMPO INICIAL DE 154hs
                                                                         // (JUEGO NUEVO)
        this.contextoDelJuego = new ContextoDelJuego(this.nombre);
        this.ordenDeArresto = new OrdenDeArresto(this.nombre);
        // LA CIUDAD ACTUAL (DONDE COMIENZA EL JUEGO) SERA EL PRIMER EDIFICIO DE LA RUTA DE ESCAPE
        // DEL LADRON
        this.ciudadActual =
            new Ciudad(Repositorio.cargarPaisActual(this.nombre));

        this.ciudadActual.setVisitada(Boolean.TRUE); // Primera ciudad se visita ni bien comienza el
                                                     // juego
        this.pistaActual = new Pista(this.nombre);

        this.actualizarDestinos();
    }

    private void actualizarDestinos() {

        ArrayList<Ciudad> listaDeDestinos = new ArrayList<Ciudad>();
        ArrayList<String> paisesPosibles = Repositorio.getTodosLosPaises();
        int cantidadDePaisesAAgregar =
            Constants.CANTIDAD_DE_CIUDADES_DESTINO_A_AGREGAR;

        if (this.estaEnCiudadIncorrecta) {
            listaDeDestinos.add(this.ciudadDestinoPorMalViaje);
            paisesPosibles =
                this.filtrarPaisesPosibles(paisesPosibles,
                    this.ciudadActual.getPais(),
                    this.ciudadDestinoPorMalViaje.getPais());
        } else {
            if (!(this.getContextoDelJuego().getCaso()
                .todasLasCiudadesVisitadas())) {
                Ciudad siguienteCiudadDeEscape =
                    this.getContextoDelJuego().getCaso()
                        .getSiguienteCiudadDeEscape();
                // Agrega a la lista de destinos la ciudad correcta
                listaDeDestinos.add(siguienteCiudadDeEscape);
                paisesPosibles =
                    this.filtrarPaisesPosibles(paisesPosibles,
                        this.ciudadActual.getPais(),
                        siguienteCiudadDeEscape.getPais());
            } else {
                cantidadDePaisesAAgregar = cantidadDePaisesAAgregar + 1; // Se agregara un pais mas
                                                                         // ya que estoy en la
                                                                         // ultima ciudad
            }
        }
        for (int i = 0; i < cantidadDePaisesAAgregar; i++) {
            int indiceDelPais = (int) (Math.random() * paisesPosibles.size());
            listaDeDestinos.add(new Ciudad(paisesPosibles.get(indiceDelPais)));
            paisesPosibles.remove(indiceDelPais);
        }
        Collections.shuffle(listaDeDestinos);
        this.destinos = listaDeDestinos;
    }

    private ArrayList<String> filtrarPaisesPosibles(ArrayList<String> paisesPosibles,
                                                    String pais, String pais2) {

        paisesPosibles.remove(pais);
        paisesPosibles.remove(pais2);
        return paisesPosibles;
    }

    public void viajar(Ciudad ciudadDestino) {

        int velocidad =
            this.contextoDelJuego.getCargoPoliciaco().getCostoDeViaje();
        int distancia = (int) Mapa.getDistancia(ciudadActual, ciudadDestino);
        int tiempoViaje = Math.round(distancia / velocidad);
        Tiempo.setTiempo(Tiempo.getTiempo() - tiempoViaje);

        this.dormirSiEsNecesario(tiempoViaje); // De ser necesario, dormira
        String siguienteCiudad;

        if (this.estaEnCiudadIncorrecta) {
            siguienteCiudad = this.ciudadDestinoPorMalViaje.getNombre();
        } else {
            siguienteCiudad =
                this.getContextoDelJuego().getCaso()
                    .getSiguienteCiudadDeEscape().getNombre();
        }

        if (!ciudadDestino.getNombre().equals(siguienteCiudad)) { // Viajo a la ciudad incorrecta
            if (!this.estaEnCiudadIncorrecta) {
                ciudadDestinoPorMalViaje = this.ciudadActual;
            }
            this.estaEnCiudadIncorrecta = Boolean.TRUE;
        } else {
            ciudadDestino.setVisitada(Boolean.TRUE); // Si viajo correctamente
            this.estaEnCiudadIncorrecta = Boolean.FALSE;
            this.recibirHeridaDeCuchillo(); // Si viaja a la ciudad correcta recibe una herida que
                                            // le quita tiempo
        }
        this.ciudadActual = ciudadDestino;
        this.numeroDeEdificiosVisitados = 0; // REINICIA EL NUMERO DE EDIFICIOS VISITADOS POR NUEVA
                                             // CIUDAD
        this.actualizarDestinos();
    }

    public void dormir() {

        Tiempo.setTiempo(Tiempo.getTiempo() - Constants.TIEMPO_DORMIR);
    }

    public void entrarAEdificio(String tipoDeEdificio) {

        Edificio edificioVisitado =
            this.getCiudadActual().entrarAEdificio(tipoDeEdificio);
        this.getContextoDelJuego().setEdificioActual(edificioVisitado);
        if (!this.estaEnCiudadIncorrecta()) {
            this.pistaActual =
                new Pista(Repositorio.getPistaPais(),
                    Repositorio.getPistaLadron());
        }
        this.numeroDeEdificiosVisitados = this.numeroDeEdificiosVisitados + 1;
        // SE DESCUENTA EL TIPO POR VISITAR EL EDIFICIO
        int tiempoEnEntrarAEdificio = 0;
        switch (this.numeroDeEdificiosVisitados) {
            case 1:
                Tiempo.setTiempo(Tiempo.getTiempo()
                    - Constants.TIEMPO_ENTRAR_A_EDIFICIO_1_VEZ);
                tiempoEnEntrarAEdificio =
                    Constants.TIEMPO_ENTRAR_A_EDIFICIO_1_VEZ;
                break;

            case 2:
                Tiempo.setTiempo(Tiempo.getTiempo()
                    - Constants.TIEMPO_ENTRAR_A_EDIFICIO_2_VEZ);
                tiempoEnEntrarAEdificio =
                    Constants.TIEMPO_ENTRAR_A_EDIFICIO_2_VEZ;
                break;

            default:
                Tiempo.setTiempo(Tiempo.getTiempo()
                    - Constants.TIEMPO_ENTRAR_A_EDIFICIO_3_VEZ);
                tiempoEnEntrarAEdificio =
                    Constants.TIEMPO_ENTRAR_A_EDIFICIO_3_VEZ;
                break;
        }

        this.dormirSiEsNecesario(tiempoEnEntrarAEdificio); // De ser necesario, dormira

    }

    public void recibirHeridaDeArmaDeFuego() {

        Tiempo.setTiempo(Tiempo.getTiempo() - Constants.TIEMPO_HERIDA_ARMA);
        this.dormirSiEsNecesario(Constants.TIEMPO_HERIDA_ARMA); // De ser necesario, dormira
    }

    public void recibirHeridaDeCuchillo() {

        if (yaHeridoConCuchillo == true) {
            Tiempo.setTiempo(Tiempo.getTiempo()
                - Constants.TIEMPO_HERIDA_CUCHILLO);
        } else {
            Tiempo.setTiempo(Tiempo.getTiempo()
                - Constants.TIEMPO_HERIDA_CUCHILLO); // rareza en el enunciado : son dos horas en
                                                     // los dos casos.
            yaHeridoConCuchillo = true;
        }
        this.dormirSiEsNecesario(Constants.TIEMPO_HERIDA_CUCHILLO); // De ser necesario, dormira
    }

    public void emitirOrdenDeArresto(String apellidoDelSospechoso) // El ladron es unicamente
                                                                   // definido por su apellido :
                                                                   // generar un order de arresto es
                                                                   // igual a designar un apellido
    {

        this.ordenDeArresto.setApellido(apellidoDelSospechoso);
        this.ordenDeArresto.setFueEmitida(Boolean.TRUE);
        Tiempo.setTiempo(Tiempo.getTiempo()
            - Constants.COSTO_EMITIR_ORDEN_DE_ARRESTO);
        this.dormirSiEsNecesario(Constants.COSTO_EMITIR_ORDEN_DE_ARRESTO); // De ser necesario,
                                                                           // dormira
    }

    public void dormirSiEsNecesario(int tiempoConsumido) {

        Tiempo.cantidadDeHorasDespierto =
            Tiempo.cantidadDeHorasDespierto + tiempoConsumido;
        if (Tiempo.cantidadDeHorasDespierto >= Constants.MAXIMO_HORAS_SIN_DORMIR) {
            this.dormir();
            Tiempo.cantidadDeHorasDespierto =
                Constants.TIEMPO_DESPIERTO_LUEGO_DE_DORMIR;
        }
    }

    public Ciudad getDestino1() {

        return this.getDestinos().get(Constants.PRIMERA_CIUDAD);
    }

    public Ciudad getDestino2() {

        return this.getDestinos().get(Constants.SEGUNDA_CIUDAD);
    }

    public Ciudad getDestino3() {

        return this.getDestinos().get(Constants.TERCERA_CIUDAD);
    }

}
